#pragma once

#include <algorithm>
#include <chrono>
#include <cmath>
#include <ctime>
#include <opencv2/opencv.hpp>

#include "../util/Utility.h"
#include "ArmorBase.h"

namespace hitcrt {

// 灯条检测基类,代码建议继承自该类实现
class BarDetectorBase {
   public:
    BarDetectorBase(const int contourSizeMin, const int contourSizeMax,
                    const float areaMin, const float areaMax,
                    const float lengthMin, const float lengthMax,
                    const float aspectRatioMin, const float aspectRatioMax,
                    const float colorRatioThresh, const float slopeThresh,
                    const int colorDiffThresh)
        : m_contourSizeMin(contourSizeMin),
          m_contourSizeMax(contourSizeMax),
          m_areaMin(areaMin),
          m_areaMax(areaMax),
          m_lengthMin(lengthMin),
          m_lengthMax(lengthMax),
          m_aspectRatioMin(aspectRatioMin),
          m_aspectRatioMax(aspectRatioMax),
          m_colorRatioThresh(colorRatioThresh),
          m_slopeThresh(slopeThresh),
          m_colorDiffThresh(colorDiffThresh) {}
    BarDetectorBase() = default;
    virtual ~BarDetectorBase() {};

    virtual bool detect(const ROI roi, const cv::Mat &mask,
                        const cv::Mat &enemyChannel, const cv::Mat &selfChannel,
                        std::vector<LightBar> &lightBars);

    // getters
    const std::vector<std::vector<cv::Point>> &getContours() const {
        return m_contours;
    };

    const std::vector<std::vector<cv::Point2f>> &getInsidePointsVec() const {
        return m_insidePointsVec;
    };

    const std::vector<cv::Rect> &getBoundingRects() const {
        return m_boundingRects;
    };

    const std::vector<cv::RotatedRect> &getRotatedRects() const {
        return m_rotatedRects;
    };

   protected:
    void clearVectors();  // 清空vector变量

    bool findLightBars(const ROI roi, const cv::Mat &enemyChannel,
                       const cv::Mat &selfChannel,
                       std::vector<LightBar> &lightBars);

    bool isLightBar(const std::vector<cv::Point> &contour,
                    const cv::Mat &enemyChannel, const cv::Mat &selfChannel,
                    LightBar &bar);

    bool findContours(const cv::Mat &mask);

    virtual bool checkGeometryFeature(const std::vector<cv::Point> &contour,
                                      LightBar &bar) = 0;

    virtual bool checkColor(const std::vector<cv::Point> &contour,
                            const cv::Mat &enemyChannel,
                            const cv::Mat &selfChannel, LightBar &bar) = 0;

    virtual bool checkDirection(LightBar &bar) = 0;

    virtual void getPoints(const std::vector<cv::Point> &contour, const ROI roi,
                           LightBar &bar) = 0;

    // 成员变量
    // 阈值参数
    float m_colorRatioThresh;  // 颜色比例阈值
    float m_slopeThresh;       //
    int m_colorDiffThresh;  // 颜色差异阈值,即敌方通道 - 我方通道像素值阈值
    // 范围参数
    int m_contourSizeMin;    // 图像内轮廓数目
    int m_contourSizeMax;    // 图像内轮廓数目最大值
    float m_areaMin;         // 连通域最小面积
    float m_areaMax;         // 连通域最大面积
    float m_lengthMin;       // 灯条最小长度
    float m_lengthMax;       // 灯条最大长度
    float m_aspectRatioMin;  // 最低宽高比
    float m_aspectRatioMax;  // 最大宽高比
    std::vector<std::vector<cv::Point>> m_contours;
    std::vector<std::vector<cv::Point2f>> m_insidePointsVec;
    std::vector<cv::Rect> m_boundingRects;
    std::vector<cv::RotatedRect> m_rotatedRects;
    cv::Vec4f m_line;  // 拟合曲线
};
/// TODO 需要继承、override和补充声明 ///
class BarDetector final : public BarDetectorBase {
   public:
    BarDetector(const int contourSizeMin, const int contourSizeMax,
                const float areaMin, const float areaMax, const float lengthMin,
                const float lengthMax, const float aspectRatioMin,
                const float aspectRatioMax, const float colorRatioThresh,
                const float slopeThresh, const int colorDiffThresh)
        : BarDetectorBase(contourSizeMin, contourSizeMax, areaMin, areaMax,
                          lengthMin, lengthMax, aspectRatioMin, aspectRatioMax,
                          colorRatioThresh, slopeThresh, colorDiffThresh) {}

    bool checkGeometryFeature(const std::vector<cv::Point> &contour,
                              LightBar &bar);
    bool checkGeometryFeatureImpl(const std::vector<cv::Point> &contour,
                                  LightBar &bar);
    bool checkColor(const std::vector<cv::Point> &contour,
                    const cv::Mat &enemyChannel, const cv::Mat &selfChannel,
                    LightBar &bar);
    bool checkColorImpl(const std::vector<cv::Point> &contour,
                        const cv::Mat &enemyChannel, const cv::Mat &selfChannel,
                        std::vector<cv::Point2f> &insidePoints, LightBar &bar);
    bool checkDirection(LightBar &bar);
    bool checkDirectionImpl(const std::vector<cv::Point2f> &insidePoints,
                            LightBar &bar);
    void getPoints(const std::vector<cv::Point> &contour, const ROI roi,
                   LightBar &bar);
    void getEndPointsImpl(const std::vector<cv::Point> &contour, LightBar &bar);
};
}  // namespace hitcrt
